#!/usr/bin/python3
# -*- coding: utf-8 -*
"""
Description: Mix infomation parser.
Class: MixInfoParser.
"""
from pygrok import Grok

from ..libs.log import LOGGER
from .config import ConfigParser
from .table import TableParser


class MixInfoParser(ConfigParser, TableParser):
    """
    class MixInfoParser is the parser that parses the mixed information to the formatted data.
    """

    def parse_content(self, key, content):
        """
        Parse the mixed information to formatted data.

        Args:
            key (str): the main key of the content.
            content (list): raw data.

        Returns:
            dict: parsed content.
            bool: parse succeed or fail.
        """
        # divide content into blocks
        content = self.parse_to_block(key, content)
        # block failed.
        if isinstance(content, list):
            return content, False
        LOGGER.debug(content)
        res = {}
        # if the log types are not correct, use the old parse method.
        if len(content) != len(self.param_config['log_type']):
            LOGGER.warning("Log types and multiline regex patterns are not matched in\
                '%s', try to find matched type.", key)
            return self.parse_content_old(key, content)

        # determine whether to use custom regex pattern.
        regex_pattern = self.param_config.get('regex_pattern')
        regex_pattern = regex_pattern if isinstance(
            regex_pattern, list) else [regex_pattern]
        use_regex_pattern = False

        if regex_pattern is not None:
            if len(regex_pattern) == len(content):
                use_regex_pattern = True
            else:
                LOGGER.warning("Regex patterns and content are not matched in '%s',\
                    choose to ignore the regex pattern.", key)

        for index, (k, value) in enumerate(content.items()):
            file_type = self.param_config['log_type'][index]

            if file_type == 'content' or len(value) == 0:
                res[k] = value
                continue

            if k not in self.param_config.keys():
                self.try_to_find_matched_pattern(
                    k, value, use_regex_pattern, index)

            matched_grok = self.param_config[k].get('matched_grok')
            matched_pattern = self.param_config[k].get('matched_pattern')

            if matched_grok is None:
                res[k] = value
                continue

            LOGGER.debug(matched_pattern)
            res[k] = self.parse_df_content(
                file_type, value, matched_grok, matched_pattern)

        res = list(res.values())[0] if len(res) == 1 else res

        return res, True

    def try_to_find_matched_pattern(self, key, value, use_regex_pattern, index):
        """
        find matched pattern for key.

        Args:
            key (str): the key of the content.
            value (list): raw data.
            use_regex_pattern (bool): whether to use regex pattern.
            index (int)

        Returns:
        """
        second = value[1] if len(value) > 1 else None
        file_type = self.param_config['log_type'][index]

        if use_regex_pattern:
            matched_grok, matched_pattern = self.get_matched_pattern(
                key, value[0], index)

        if matched_grok is None:
            matched_grok, matched_pattern = self.find_matched_pattern_by_type(
                value[0], file_type, second)

        if matched_grok is None:
            LOGGER.error(
                "No matchede type for '%s', return raw content.", key)

        self.param_config[key] = {}
        self.param_config[key]['matched_grok'] = matched_grok
        self.param_config[key]['matched_pattern'] = matched_pattern

    def parse_df_content(self, file_type, content, matched_grok, matched_pattern):
        """
        parse accroding to its type.

        Args:
            file_type (str): log type.
            content (list): data.
            matched_grok (grok object): compiled pattern.
            matched_pattern (str): matched pattern.

        Returns:
            dict or list: result.
        """
        if file_type == 'config':
            content = self.get_active_lines(content)
            return self.parse_config(content, matched_grok)
        if file_type == 'table':
            matched_pattern = self.rename_pattern(
                content[0], matched_grok, matched_pattern)
            matched_grok = Grok(
                matched_pattern, self.regex_config.get('custom_file'))
            res, _ = self.parse_table(content, matched_grok)
            return res
        if file_type == 'log':
            return self.parse_log(content, matched_grok)
        return content

    def parse_content_old(self, key, content):
        """
        Parse the mixed information to formatted data in case that we don't know the log type.

        Args:
            key (str): the main key of the content.
            content (str): blocked data.

        Returns:
            dict: parsed content.
            bool: parse succeed or fail.
        """
        res = {}

        for k, value in content.items():
            if len(value) == 0:
                res[k] = value
                continue
            head = value[0]

            if k not in self.param_config.keys():
                # find matched type and pattern
                matched_type, matched_grok, matched_index = self.find_matched_pattern(
                    head, self.regex_config.get('grok'), self.param_config['log_type'])
                self.param_config[k] = {}
                self.param_config[k]['matched_type'] = matched_type
                if matched_type is None:
                    matched_pattern = None
                    LOGGER.error(
                        "No matched type for '%s' in the '%s' file, return raw content.", k, key)
                else:
                    matched_pattern = self.regex_config.get(
                        'patterns')[matched_type][matched_index]
                self.param_config[k]['matched_grok'] = matched_grok
                self.param_config[k]['matched_pattern'] = matched_pattern
            else:
                matched_grok = self.param_config[k].get('matched_grok')
                matched_type = self.param_config[k].get('matched_type')
                matched_pattern = self.param_config[k].get('matched_pattern')

            if matched_type == 'config':
                value = self.get_active_lines(value)
                res[k] = self.parse_config(value, matched_grok)
            elif matched_type == 'table':
                value = self.get_active_lines(value, "")
                matched_pattern = self.rename_pattern(
                    head, matched_grok, matched_pattern)
                matched_grok = Grok(
                    matched_pattern, self.regex_config.get('custom_file'))
                res[k], _ = self.parse_table(value, matched_grok)
            elif matched_type == 'log':
                res[k] = self.parse_log(value, matched_grok)
            elif matched_type is None:
                res[k] = value

        return res, True

    @staticmethod
    def find_matched_pattern(head, grok, log_type):
        """
        Find the matched pattern.

        Args:
            head (str): head of the content, just used to find the matched pattern.
            grok (dict): compiled patterns.
            log_type (list)：all mixed types.

        Returns:
            str: matched type.
            grok object: matched compiled pattern.
            int: matched index.
        """

        if grok is None:
            return None, None, None

        for matched_type in log_type:
            if matched_type not in grok.keys():
                continue
            for matched_index, matched_grok in enumerate(grok.get(matched_type)):
                tmp = matched_grok.match(head)
                if tmp is not None:
                    return matched_type, matched_grok, matched_index

        return None, None, None

    @staticmethod
    def parse_log(content, grok):
        """
        Simple log parse.

        Args:
            content (list): raw content.
            grok (grok object): matched compiled pattern.
        """
        data = []
        for line in content:
            log_formated = grok.match(line)
            if log_formated is None:
                continue
            data.append(log_formated)

        return data


def get_class():
    """
    get MinInfoParser class.

    Args:

    Returns:
        class
    """
    return MixInfoParser
